﻿using CodeSmith.Core.Collections;
using SchemaExplorer;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

public class MySqlSchemaProvider : IDbSchemaProvider, INamedObject
{
    public string Name => "MySqlSchemaProvider";

    public string Description => "MySQL Schema Provider";

    public string GetDatabaseName(string connectionString)
    {
        Regex regex = new Regex("Database\\W*=\\W*(?<database>[^;]*)", RegexOptions.IgnoreCase);
        Match match = regex.Match(connectionString);
        if (match.Success)
        {
            return match.Groups["database"].ToString();
        }
        return connectionString;
    }

    public string GetViewText(string connectionString, ViewSchema view)
    {
        StringBuilder stringBuilder = new StringBuilder();
        string commandText = $"SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '{view.Database.Name}' AND TABLE_NAME = '{view.Name}'";
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    stringBuilder.Append(dataReader.GetString(0));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return stringBuilder.ToString();
    }

    public TableSchema[] GetTables(string connectionString, DatabaseSchema database)
    {
        string commandText = $"SELECT TABLE_NAME, '' OWNER, CREATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{database.Name}' AND TABLE_TYPE = 'BASE TABLE' ORDER BY 1";
        List<TableSchema> list = new List<TableSchema>();
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    DateTime dateCreated = (!dataReader.IsDBNull(2)) ? dataReader.GetDateTime(2) : DateTime.MinValue;
                    list.Add(new TableSchema(database, dataReader.GetString(0), dataReader.GetString(1), dateCreated));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return list.ToArray();
    }

    public ViewSchema[] GetViews(string connectionString, DatabaseSchema database)
    {
        string commandText = $"SELECT TABLE_NAME, '' OWNER, CREATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{database.Name}' AND TABLE_TYPE = 'VIEW' ORDER BY 1";
        List<ViewSchema> list = new List<ViewSchema>();
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    DateTime dateCreated = (!dataReader.IsDBNull(2)) ? dataReader.GetDateTime(2) : DateTime.MinValue;
                    list.Add(new ViewSchema(database, dataReader.GetString(0), dataReader.GetString(1), dateCreated));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return list.ToArray();
    }

    public CommandSchema[] GetCommands(string connectionString, DatabaseSchema database)
    {
        string commandText = $"SELECT ROUTINE_NAME, '' OWNER, CREATED FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '{database.Name}' AND ROUTINE_TYPE = 'PROCEDURE' ORDER BY 1";
        List<CommandSchema> list = new List<CommandSchema>();
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    list.Add(new CommandSchema(database, dataReader.GetString(0), dataReader.GetString(1), dataReader.GetDateTime(2)));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return list.ToArray();
    }

    public DataTable GetTableData(string connectionString, TableSchema table)
    {
        string commandText = $"SELECT * FROM {table.Name}";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        if (dataSet.Tables.Count > 0)
        {
            return dataSet.Tables[0];
        }
        return new DataTable(table.Name);
    }

    public DataTable GetViewData(string connectionString, ViewSchema view)
    {
        string commandText = $"SELECT * FROM {view.Name}";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        if (dataSet.Tables.Count > 0)
        {
            return dataSet.Tables[0];
        }
        return new DataTable(view.Name);
    }

    public ColumnSchema[] GetTableColumns(string connectionString, TableSchema table)
    {
        string commandText = $"SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, CASE IS_NULLABLE WHEN 'NO' THEN 0 ELSE 1 END IS_NULLABLE, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{table.Database.Name}' AND TABLE_NAME = '{table.Name}' ORDER BY ORDINAL_POSITION";
        List<ColumnSchema> list = new List<ColumnSchema>();
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    string @string = dataReader.GetString(0);
                    string string2 = dataReader.GetString(1);
                    long num = (!dataReader.IsDBNull(2)) ? dataReader.GetInt64(2) : 0;
                    byte precision = (byte)((!dataReader.IsDBNull(3)) ? dataReader.GetInt32(3) : 0);
                    int scale = (!dataReader.IsDBNull(4)) ? dataReader.GetInt32(4) : 0;
                    bool allowDBNull = !dataReader.IsDBNull(5) && dataReader.GetBoolean(5);
                    string string3 = dataReader.GetString(6);
                    int size = (int)((num < int.MaxValue) ? num : int.MaxValue);
                    bool isUnsigned = string3.IndexOf("unsigned") > -1;
                    DbType dbType = GetDbType(string2, isUnsigned);
                    list.Add(new ColumnSchema(table, @string, dbType, string2, size, precision, scale, allowDBNull));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return list.ToArray();
    }

    public ViewColumnSchema[] GetViewColumns(string connectionString, ViewSchema view)
    {
        string commandText = $"SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, CASE IS_NULLABLE WHEN 'NO' THEN 0 ELSE 1 END IS_NULLABLE, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{view.Database.Name}' AND TABLE_NAME = '{view.Name}'ORDER BY ORDINAL_POSITION";
        List<ViewColumnSchema> list = new List<ViewColumnSchema>();
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    string @string = dataReader.GetString(0);
                    string string2 = dataReader.GetString(1);
                    long num = (!dataReader.IsDBNull(2)) ? dataReader.GetInt64(2) : 0;
                    byte precision = (byte)((!dataReader.IsDBNull(3)) ? dataReader.GetInt32(3) : 0);
                    int scale = (!dataReader.IsDBNull(4)) ? dataReader.GetInt32(4) : 0;
                    bool allowDBNull = !dataReader.IsDBNull(5) && dataReader.GetBoolean(5);
                    string string3 = dataReader.GetString(6);
                    int size = (int)((num < int.MaxValue) ? num : int.MaxValue);
                    bool isUnsigned = string3.IndexOf("unsigned") > -1;
                    DbType dbType = GetDbType(string2, isUnsigned);
                    list.Add(new ViewColumnSchema(view, @string, dbType, string2, size, precision, scale, allowDBNull));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return list.ToArray();
    }

    public PrimaryKeySchema GetTablePrimaryKey(string connectionString, TableSchema table)
    {
        string commandText = $"SELECT t1.CONSTRAINT_NAME, t1.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE t1  INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t2  ON t2.TABLE_SCHEMA = t1.TABLE_SCHEMA  AND t2.TABLE_NAME = t1.TABLE_NAME  AND t2.CONSTRAINT_NAME = t1.CONSTRAINT_NAME WHERE t1.TABLE_SCHEMA = '{table.Database.Name}' AND t1.TABLE_NAME = '{table.Name}' AND t2.CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY t1.ORDINAL_POSITION";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
        {
            string name = dataSet.Tables[0].Rows[0]["CONSTRAINT_NAME"].ToString();
            string[] array = new string[dataSet.Tables[0].Rows.Count];
            for (int i = 0; i < dataSet.Tables[0].Rows.Count; i++)
            {
                array[i] = dataSet.Tables[0].Rows[i]["COLUMN_NAME"].ToString();
            }
            return new PrimaryKeySchema(table, name, array);
        }
        return null;
    }

    public TableKeySchema[] GetTableKeys(string connectionString, TableSchema table)
    {
        List<TableKeySchema> list = new List<TableKeySchema>();
        list.AddRange(GetMyTableKeys(connectionString, table));
        list.AddRange(GetOthersTableKeys(connectionString, table));
        return list.ToArray();
    }

    private IEnumerable<TableKeySchema> GetMyTableKeys(string connectionString, SchemaObjectBase table)
    {
        string commandText = $"SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS t1 WHERE t1.TABLE_SCHEMA = '{table.Database.Name}' AND t1.TABLE_NAME = '{table.Name}'  AND CONSTRAINT_TYPE = 'FOREIGN KEY'";
        string commandText2 = $"SELECT t1.CONSTRAINT_NAME, t1.COLUMN_NAME, t1.POSITION_IN_UNIQUE_CONSTRAINT,  t1.REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE t1  INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t2  ON t2.TABLE_SCHEMA = t1.TABLE_SCHEMA  AND t2.TABLE_NAME = t1.TABLE_NAME  AND t2.CONSTRAINT_NAME = t1.CONSTRAINT_NAME WHERE t1.TABLE_SCHEMA = '{table.Database.Name}' AND t1.TABLE_NAME = '{table.Name}'  AND t2.CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY t1.CONSTRAINT_NAME, t1.POSITION_IN_UNIQUE_CONSTRAINT";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            using (DbCommand dbCommand = dbConnection.CreateCommand())
            {
                dbCommand.CommandText = commandText;
                dbCommand.Connection = dbConnection;
                dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        using (DbConnection dbConnection2 = dbProviderFactory.CreateConnection())
        {
            dbConnection2.ConnectionString = connectionString;
            dbConnection2.Open();
            using (DbCommand dbCommand2 = dbConnection2.CreateCommand())
            {
                dbCommand2.CommandText = commandText2;
                dbCommand2.Connection = dbConnection2;
                dataSet.Tables.Add(ConvertDataReaderToDataTable(dbCommand2.ExecuteReader()));
            }
            if (dbConnection2.State != 0)
            {
                dbConnection2.Close();
            }
        }
        List<TableKeySchema> list = new List<TableKeySchema>();
        if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
        {
            dataSet.Relations.Add("Contraint_to_Keys", dataSet.Tables[0].Columns["CONSTRAINT_NAME"], dataSet.Tables[1].Columns["CONSTRAINT_NAME"]);
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                string name = row["CONSTRAINT_NAME"].ToString();
                List<DataRow> list2 = new List<DataRow>(row.GetChildRows("Contraint_to_Keys"));
                List<string> list3 = new List<string>(list2.Count);
                List<string> list4 = new List<string>(list2.Count);
                string name2 = table.Name;
                string primaryKeyTable = list2[0]["REFERENCED_TABLE_NAME"].ToString();
                foreach (DataRow item in list2)
                {
                    list4.Add(item["COLUMN_NAME"].ToString());
                    list3.Add(item["REFERENCED_COLUMN_NAME"].ToString());
                }
                list.Add(new TableKeySchema(table.Database, name, list4.ToArray(), name2, list3.ToArray(), primaryKeyTable));
            }
        }
        if (list.Count > 0)
        {
            return list;
        }
        return new List<TableKeySchema>();
    }

    private IEnumerable<TableKeySchema> GetOthersTableKeys(string connectionString, SchemaObjectBase table)
    {
        string commandText = $"SELECT DISTINCT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE t1 WHERE t1.TABLE_SCHEMA = '{table.Database.Name}' AND t1.REFERENCED_TABLE_NAME = '{table.Name}'";
        string commandText2 = $"SELECT t1.CONSTRAINT_NAME, t1.TABLE_NAME, t1.COLUMN_NAME, t1.POSITION_IN_UNIQUE_CONSTRAINT,  t1.REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE t1  INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS t2  ON t2.TABLE_SCHEMA = t1.TABLE_SCHEMA  AND t2.TABLE_NAME = t1.TABLE_NAME  AND t2.CONSTRAINT_NAME = t1.CONSTRAINT_NAME WHERE t1.TABLE_SCHEMA = '{table.Database.Name}' AND t1.REFERENCED_TABLE_NAME = '{table.Name}'  AND t2.CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY t1.CONSTRAINT_NAME, t1.POSITION_IN_UNIQUE_CONSTRAINT";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            using (DbCommand dbCommand = dbConnection.CreateCommand())
            {
                dbCommand.CommandText = commandText;
                dbCommand.Connection = dbConnection;
                dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        using (DbConnection dbConnection2 = dbProviderFactory.CreateConnection())
        {
            dbConnection2.ConnectionString = connectionString;
            dbConnection2.Open();
            using (DbCommand dbCommand2 = dbConnection2.CreateCommand())
            {
                dbCommand2.CommandText = commandText2;
                dbCommand2.Connection = dbConnection2;
                dataSet.Tables.Add(ConvertDataReaderToDataTable(dbCommand2.ExecuteReader()));
            }
            if (dbConnection2.State != 0)
            {
                dbConnection2.Close();
            }
        }
        List<TableKeySchema> list = new List<TableKeySchema>();
        if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
        {
            dataSet.Relations.Add("Contraint_to_Keys", dataSet.Tables[0].Columns["CONSTRAINT_NAME"], dataSet.Tables[1].Columns["CONSTRAINT_NAME"]);
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                string name = row["CONSTRAINT_NAME"].ToString();
                List<DataRow> list2 = new List<DataRow>(row.GetChildRows("Contraint_to_Keys"));
                List<string> list3 = new List<string>(list2.Count);
                List<string> list4 = new List<string>(list2.Count);
                string foreignKeyTable = list2[0]["TABLE_NAME"].ToString();
                string primaryKeyTable = list2[0]["REFERENCED_TABLE_NAME"].ToString();
                foreach (DataRow item in list2)
                {
                    list4.Add(item["COLUMN_NAME"].ToString());
                    list3.Add(item["REFERENCED_COLUMN_NAME"].ToString());
                }
                list.Add(new TableKeySchema(table.Database, name, list4.ToArray(), foreignKeyTable, list3.ToArray(), primaryKeyTable));
            }
        }
        if (list.Count > 0)
        {
            return list;
        }
        return new List<TableKeySchema>();
    }

    private DataSet ConvertDataReaderToDataSet(IDataReader reader)
    {
        DataSet dataSet = new DataSet();
        dataSet.Tables.Add(ConvertDataReaderToDataTable(reader));
        return dataSet;
    }

    private DataTable ConvertDataReaderToDataTable(IDataReader reader)
    {
        DataTable schemaTable = reader.GetSchemaTable();
        DataTable dataTable = new DataTable();
        foreach (DataRow row in schemaTable.Rows)
        {
            string columnName = (string)row["ColumnName"];
            DataColumn column = new DataColumn(columnName, (Type)row["DataType"]);
            dataTable.Columns.Add(column);
        }
        while (reader.Read())
        {
            DataRow dataRow2 = dataTable.NewRow();
            for (int i = 0; i <= reader.FieldCount - 1; i++)
            {
                dataRow2[i] = reader.GetValue(i);
            }
            dataTable.Rows.Add(dataRow2);
        }
        return dataTable;
    }

    public IndexSchema[] GetTableIndexes(string connectionString, TableSchema table)
    {
        string commandText = $"SELECT INDEX_NAME, COUNT(*) AS COLUMN_COUNT, MAX(NON_UNIQUE) NON_UNIQUE, CASE INDEX_NAME WHEN 'PRIMARY' THEN 1 ELSE 0 END IS_PRIMARY FROM INFORMATION_SCHEMA.STATISTICS WHERE  TABLE_SCHEMA = '{table.Database.Name}' AND TABLE_NAME = '{table.Name}' GROUP BY INDEX_NAME ORDER BY INDEX_NAME;";
        string commandText2 = $"SELECT INDEX_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE  TABLE_SCHEMA = '{table.Database.Name}' AND TABLE_NAME = '{table.Name}' ORDER BY INDEX_NAME, SEQ_IN_INDEX;";
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DataSet dataSet;
        using (DbConnection dbConnection = dbProviderFactory.CreateConnection())
        {
            dbConnection.ConnectionString = connectionString;
            dbConnection.Open();
            using (DbCommand dbCommand = dbConnection.CreateCommand())
            {
                dbCommand.CommandText = commandText;
                dbCommand.Connection = dbConnection;
                dataSet = ConvertDataReaderToDataSet(dbCommand.ExecuteReader());
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        using (DbConnection dbConnection2 = dbProviderFactory.CreateConnection())
        {
            dbConnection2.ConnectionString = connectionString;
            dbConnection2.Open();
            using (DbCommand dbCommand2 = dbConnection2.CreateCommand())
            {
                dbCommand2.CommandText = commandText2;
                dbCommand2.Connection = dbConnection2;
                dataSet.Tables.Add(ConvertDataReaderToDataTable(dbCommand2.ExecuteReader()));
            }
            if (dbConnection2.State != 0)
            {
                dbConnection2.Close();
            }
        }
        List<IndexSchema> list = new List<IndexSchema>();
        if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
        {
            dataSet.Relations.Add("INDEX_to_COLUMNS", dataSet.Tables[0].Columns["INDEX_NAME"], dataSet.Tables[1].Columns["INDEX_NAME"]);
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                string name = row["INDEX_NAME"].ToString();
                bool flag = (int)row["IS_PRIMARY"] == 1;
                bool isUnique = (long)row["NON_UNIQUE"] != 1;
                bool isClustered = flag;
                List<DataRow> list2 = new List<DataRow>(row.GetChildRows("INDEX_to_COLUMNS"));
                List<string> list3 = new List<string>(list2.Count);
                foreach (DataRow item in list2)
                {
                    list3.Add(item["COLUMN_NAME"].ToString());
                }
                list.Add(new IndexSchema(table, name, flag, isUnique, isClustered, list3.ToArray()));
            }
        }
        if (list.Count > 0)
        {
            return list.ToArray();
        }
        return new List<IndexSchema>().ToArray();
    }

    public string GetCommandText(string connectionString, CommandSchema commandSchema)
    {
        StringBuilder stringBuilder = new StringBuilder();
        string commandText = $"SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '{commandSchema.Database.Name}' AND ROUTINE_NAME = '{commandSchema.Name}'";
        using (DbConnection dbConnection = CreateConnection(connectionString))
        {
            dbConnection.Open();
            DbCommand dbCommand = dbConnection.CreateCommand();
            dbCommand.CommandText = commandText;
            dbCommand.Connection = dbConnection;
            using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
            {
                while (dataReader.Read())
                {
                    stringBuilder.Append(dataReader.GetString(0));
                }
                if (!dataReader.IsClosed)
                {
                    dataReader.Close();
                }
            }
            if (dbConnection.State != 0)
            {
                dbConnection.Close();
            }
        }
        return stringBuilder.ToString();
    }

    public ParameterSchema[] GetCommandParameters(string connectionString, CommandSchema command)
    {
        throw new NotSupportedException("GetCommandParameters() is not supported in this release.");
    }

    public CommandResultSchema[] GetCommandResultSchemas(string connectionString, CommandSchema command)
    {
        throw new NotSupportedException("GetCommandResultSchemas() is not supported in this release.");
    }

    public ExtendedProperty[] GetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
    {
        List<ExtendedProperty> list = new List<ExtendedProperty>();
        if (schemaObject is ColumnSchema)
        {
            ColumnSchema columnSchema = schemaObject as ColumnSchema;
            string commandText = $"SELECT EXTRA, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{columnSchema.Table.Database.Name}' AND TABLE_NAME = '{columnSchema.Table.Name}' AND COLUMN_NAME = '{columnSchema.Name}'";
            using (DbConnection dbConnection = CreateConnection(connectionString))
            {
                dbConnection.Open();
                DbCommand dbCommand = dbConnection.CreateCommand();
                dbCommand.CommandText = commandText;
                dbCommand.Connection = dbConnection;
                using (IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    while (dataReader.Read())
                    {
                        string text = dataReader.GetString(0).ToLower();
                        bool flag = dataReader.IsDBNull(1);
                        string value = "";
                        if (!flag)
                        {
                            value = dataReader.GetString(1).ToUpper();
                        }
                        string value2 = dataReader.GetString(2).ToUpper();
                        bool flag2 = text.IndexOf("auto_increment") > -1;
                        list.Add(new ExtendedProperty("CS_IsIdentity", flag2, columnSchema.DataType));
                        if (flag2)
                        {
                            list.Add(new ExtendedProperty("CS_IdentitySeed", 1, columnSchema.DataType));
                            list.Add(new ExtendedProperty("CS_IdentityIncrement", 1, columnSchema.DataType));
                        }
                        string comment = dataReader.GetString(3);
                        list.Add(new ExtendedProperty("CS_ColumnDefaultIsNull", flag, DbType.Boolean));
                        list.Add(new ExtendedProperty("CS_Default", value, DbType.String));
                        list.Add(new ExtendedProperty("CS_ColumnDefault", value, DbType.String));
                        list.Add(new ExtendedProperty("CS_SystemType", value2, DbType.String));
                        list.Add(new ExtendedProperty("CS_ColumnType", value2, DbType.String));
                        list.Add(new ExtendedProperty("CS_ColumnExtra", text.ToUpper(), DbType.String));
                        list.Add(new ExtendedProperty("CS_Description", comment, DbType.String));
                    }
                    if (!dataReader.IsClosed)
                    {
                        dataReader.Close();
                    }
                }
                if (dbConnection.State != 0)
                {
                    dbConnection.Close();
                }
            }
        }
        if (schemaObject is TableSchema)
        {
            TableSchema tableSchema = schemaObject as TableSchema;
            string commandText2 = $"SHOW CREATE TABLE `{tableSchema.Database.Name}`.`{tableSchema.Name}`";
            using (DbConnection dbConnection2 = CreateConnection(connectionString))
            {
                dbConnection2.Open();
                //增加表的注释 开始
                DbCommand tableCommentCommand = dbConnection2.CreateCommand();
                tableCommentCommand.CommandText = $"SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='{tableSchema.Database.Name}' AND TABLE_NAME='{tableSchema.Name}'";
                tableCommentCommand.Connection = dbConnection2;
                using(IDataReader tableCommentReader = tableCommentCommand.ExecuteReader())
                {
                    if (tableCommentReader.Read())
                    {
                        list.Add(new ExtendedProperty("CS_Description", tableCommentReader.GetString(0), DbType.String));
                    }
                    if (!tableCommentReader.IsClosed)
                    {
                        tableCommentReader.Close();
                    }
                }
                //增加表的注释 结束
                DbCommand dbCommand2 = dbConnection2.CreateCommand();
                dbCommand2.CommandText = commandText2;
                dbCommand2.Connection = dbConnection2;
                using (IDataReader dataReader2 = dbCommand2.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    while (dataReader2.Read())
                    {
                        string @string = dataReader2.GetString(1);
                        list.Add(new ExtendedProperty("CS_CreateTableScript", @string, DbType.String));
                    }
                    if (!dataReader2.IsClosed)
                    {
                        dataReader2.Close();
                    }
                }
                if (dbConnection2.State != 0)
                {
                    dbConnection2.Close();
                }
            }
        }
        return list.ToArray();
    }

    public void SetExtendedProperties(string connectionString, SchemaObjectBase schemaObject)
    {
        throw new NotImplementedException("This method has not been implemented");
    }

    private static DbProviderFactory CreateDbProviderFactory()
    {
        return DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
    }

    private static DbConnection CreateConnection(string connectionString)
    {
        DbProviderFactory dbProviderFactory = CreateDbProviderFactory();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        dbConnection.ConnectionString = connectionString;
        return dbConnection;
    }

    private static DbType GetDbType(string type, bool isUnsigned)
    {
        switch (type.ToLower())
        {
            case "bit":
                return DbType.UInt16;
            case "tinyint":
                if (!isUnsigned)
                {
                    return DbType.SByte;
                }
                return DbType.Byte;
            case "smallint":
                if (!isUnsigned)
                {
                    return DbType.Int16;
                }
                return DbType.UInt16;
            case "year":
            case "mediumint":
            case "int":
                if (!isUnsigned)
                {
                    return DbType.Int32;
                }
                return DbType.UInt32;
            case "bigint":
                if (!isUnsigned)
                {
                    return DbType.Int64;
                }
                return DbType.UInt64;
            case "float":
                return DbType.Single;
            case "double":
                return DbType.Double;
            case "decimal":
                return DbType.Decimal;
            case "date":
                return DbType.Date;
            case "datetime":
                return DbType.DateTime;
            case "timestamp":
                return DbType.DateTime;
            case "time":
                return DbType.Time;
            case "enum":
            case "set":
            case "tinytext":
            case "mediumtext":
            case "longtext":
            case "text":
            case "char":
            case "varchar":
                return DbType.String;
            case "binary":
            case "varbinary":
            case "tinyblob":
            case "blob":
            case "longblob":
                return DbType.Binary;
            default:
                return DbType.Object;
        }
    }
}
